package mylogger

import (
	"fmt"
	"os"
	"path"
	"time"
)

// 忘文件里面写日志的代码

type FileLogger struct {
	level    Level
	filename string
	filepath string
	file     *os.File
	errFile  *os.File
	maxSize  int64
}

// 文件结构体的构造函数
func NewFileLogger(levelStr string, filepath, filename string) *FileLogger {
	logLevel := parseLogLevel(levelStr)
	f1 := &FileLogger{
		level:    logLevel,
		filename: filename,
		filepath: filepath,
		maxSize:  10 * 1024 * 1024, // 初始值默认10M
	}
	f1.initFile() // 根据上面的文件路径和文件名，把文件句柄赋值对应的结构体字段
	return f1
}

func (f *FileLogger) initFile() {
	logName := path.Join(f.filepath, f.filename)

	// 打开文件  赋值给结构体
	fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件%s失败, %v", logName, err))
	}
	f.file = fileObj

	// 打开错误日志的文件
	errLogName := fmt.Sprintf("%s.err", logName)
	errFileObj, err := os.OpenFile(errLogName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件%s失败, %v", errLogName, err))
	}
	f.errFile = errFileObj
}

// 检查是否要拆分
func (f *FileLogger) checkSplit(file *os.File) bool {
	fileInfo, _ := file.Stat()
	fileSize := fileInfo.Size()
	return fileSize >= f.maxSize // 当传进来的文件 大于定义的文件开始切分
}

// 封装一个切分日志的方法
func (f *FileLogger) splitLogFile(file *os.File) *os.File {
	// 检查文件的大小 是否超过定义的文件大小
	// 1. 切分文件
	fileName := file.Name() // 拿到文件的完整路径
	backupname := fmt.Sprintf("%s_%v.back", fileName, time.Now().Unix())
	// 2. 把原来关闭
	file.Close()
	// 备份原来的文件
	os.Rename(fileName, backupname)
	// 新建一个文件
	fileObj, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件失败"))
	}
	return fileObj

}

// 将公用的记录日志的功能的封装成一个单独的方法
func (f FileLogger) log(level Level, format string, args ...interface{}) {
	if f.level > level {
		return
	}
	msg := fmt.Sprintf(format, args...) // 得到用户要记录的日志
	// 日志格式 [时间][文件:行号][函数名][日志级别] 日志信息
	nowStr := time.Now().Format("2006-01-02 15:04") // 当前时间

	fileName, line, funcName := getCallerInfo(3)

	logLevelStr := getLevelStr(level)
	lgoMsg := fmt.Sprintf("[%s][%s:%d][%s][%s] %s",
		nowStr, fileName, line, funcName, logLevelStr, msg)
	if f.checkSplit(f.file) {
		f.file = f.splitLogFile(f.file)
	}
	f.file = f.splitLogFile(f.file)
	fmt.Fprintln(f.file, lgoMsg) // 利用 fmt包将msg写入f.file文件中

	// 如果是err级别的错误就往errFile 或者 Fatal级别的日志里面写
	if f.level >= ErrorLevel {
		if f.checkSplit(f.file) {
			f.errFile = f.splitLogFile(f.errFile)
		}
		fmt.Fprintln(f.errFile, lgoMsg) // 记录错误日志
	}
}

// Debug debug方法
func (f *FileLogger) Debug(format string, args ...interface{}) {
	f.log(DebugLevel, format, args...)
}

// Info info级别的日志
func (f *FileLogger) Info(format string, args ...interface{}) {
	f.log(InfoLevel, format, args...)
}

// Warning warning级别的日志
func (f *FileLogger) Warning(format string, args ...interface{}) {
	f.log(WarningLevel, format, args...)
}

// Error error级别的日志
func (f *FileLogger) Error(format string, args ...interface{}) {
	f.log(ErrorLevel, format, args...)
}

// Fatal fatal级别的日志
func (f *FileLogger) Fatal(format string, args ...interface{}) {
	f.log(FatalLevel, format, args...)
}

// 关闭文件
func (f *FileLogger) Close() {
	f.file.Close()
	f.errFile.Close()
}
